<?php

namespace plugin\admin\app\controller\auth;

use plugin\admin\app\controller\Base;
use plugin\admin\app\model\AdminRule as ModelAdminRule;
use plugin\admin\app\model\AdminRuleThink;
use plugin\admin\app\Util;
use support\Request;

class AdminRule extends Base
{
    /**
     * @var AdminRule
     */
    protected $model = null;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->model = new ModelAdminRule;
    }

    /**
     * 获取权限树
     *
     * @param Request $request
     * @return \support\Response
     */
    public function tree(Request $request)
    {
        $this->syncRules();
        $items = $this->model->get();
        return $this->formatTree($items);
    }

    /**
     * 根据类同步规则到数据库
     *
     * @return void
     */
    protected function syncRules()
    {
        $items = $this->model->where('name', 'like', '%\\\\%')->get()->keyBy('name');
        $methods_in_db = [];
        $methods_in_files = [];
        foreach ($items as $item) {
            $class = $item->name;
            if (strpos($class, '@')) {
                $methods_in_db[$class] = $class;
                continue;
            }
            if (class_exists($class)) {
                $reflection = new \ReflectionClass($class);
                $properties = $reflection->getDefaultProperties();
                $no_need_auth = array_merge($properties['noNeedLogin'] ?? [], $properties['noNeedAuth'] ?? []);
                $class = $reflection->getName();
                $pid = $item->id;
                $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
                foreach ($methods as $method) {
                    $method_name = $method->getName();
                    if (strpos($method_name, '__') === 0 || in_array($method_name, $no_need_auth)) {
                        continue;
                    }
                    $name = "$class@$method_name";
                    $methods_in_files[$name] = $name;
                    $title = Util::getCommentFirstLine($method->getDocComment()) ?: $method_name;
                    $menu = $items[$name] ?? [];
                    if ($menu) {
                        if ($menu->title != $title) {
                            ModelAdminRule::where('name', $name)->update(['title' => $title]);
                        }
                        continue;
                    }
                    $menu = new ModelAdminRule;
                    $menu->pid = $pid;
                    $menu->name = $name;
                    $menu->path = '';
                    $menu->component = '';
                    $menu->title = $title;
                    $menu->is_menu = 0;
                    $menu->save();
                }
            }
        }
        // 从数据库中删除已经不存在的方法
        $menu_names_to_del = array_diff($methods_in_db, $methods_in_files);
        if ($menu_names_to_del) {
            ModelAdminRule::whereIn('name', $menu_names_to_del)->delete();
        }
    }

    public function select(){
        $model = new AdminRuleThink;
        $data = $model->getMenuTree();
        return $this->json(0, 'ok', $data);
    }

    /**
     * 添加
     * @param Request $request
     * @return \support\Response
     */
    public function insert(Request $request)
    {
        $data = $request->post('data');
        $name = $data['name'];
        $model = new AdminRuleThink;
        if ($model->where('name', $name)->find()) {
            return $this->json(500, "菜单key $name 已经存在");
        }
        $data['path'] = (empty($data['pid']) ? '/' : '') . ltrim($data['path'], '/');
        $model->save($data);
        return $this->json(0, '',$model->id);
    }

    /**
     * 更新
     * @param Request $request
     * @return \support\Response
     */
    public function update(Request $request)
    {
        $data = $request->post();
        $model = new AdminRuleThink;
        $row = $model->where('id', $data['id'])->find();
        if (!$row) {
            return $this->json(500, '记录不存在');
        }

        if (!isset($data['pid'])) {
            $data['pid'] = 0;
        } elseif ($data['pid'] == $row['id']) {
            return $this->json(500, '不能将自己设置为上级菜单');
        }

        $model->where('id', $data['id'])->strict(false)->update($data);
        return $this->json(0,'更新成功！');
    }
    
    /**
     * 删除
     * @param Request $request
     * @return \support\Response
     * @throws \Support\Exception\BusinessException
     */
    public function delete(Request $request)
    {
        $value = $request->post('ids');
        $model = new AdminRuleThink;
        $delete_ids = $model->whereIn('id', $value)->column('id');
        if (!$delete_ids) {
            return $this->json(1, '记录不存在');
        }
        // 子规则一起删除
        $children_ids = $delete_ids;
        while($children_ids) {
            $children_ids = $model->whereIn('pid', $children_ids)->column('id');
            $delete_ids = array_merge($delete_ids, $children_ids);
        }
        $this->model->whereIn('id', $delete_ids)->delete();
        return $this->json(0);
    }
    /**
     * 一键生成菜单
     *
     * @param Request $request
     * @return \support\Response
     * @throws \Support\Exception\BusinessException
     */
    public function create(Request $request)
    {
        $path = $request->post('path');
        if(!$path){
            abort(1001,'路径未填写，请填写正确路径');
        }
        $path = trim($path);
        $pathobj = AdminRuleThink::where(['path'=>$path])->find();
        if(!$pathobj){
            abort(1001,'请创建菜单后，再点击一键生成');
        }
        $path = trim($path, '/');
        $path_arr = explode('/',$path);
        if(count($path_arr) < 3){
            abort(1001,'路径不符合规范，请重新输入');
        }

        $plug_name = array_shift($path_arr);
        array_pop($path_arr);
        $controller_name = array_pop($path_arr);
        $model_class = Util::camel($controller_name);
        $controller_class = $model_class . config('plugin.admin.app.controller_suffix');
        $model_class = $model_class . 'Think';
        $path = implode('/',$path_arr);
        $path_backslash = str_replace('/', '\\', $path);
        if ($path_backslash) {
            $controller_namespace = "plugin\\$plug_name\\app\\controller\\$path_backslash";
        } else {
            $controller_namespace = "plugin\\$plug_name\\app\\controller";
        }
        $controller_file = base_path() . '/' . str_replace('\\', '/', $controller_namespace) . "/$controller_class.php";
        $model_file = base_path() . "/plugin/$plug_name/app/model/$model_class.php";

        if (is_file($controller_file)) {
            abort(1001,substr($controller_file, strlen(base_path())) . '控制器已经存在');
        }
        if (is_file($model_file)) {
            abort(1001,substr($model_file, strlen(base_path())) . '模型已经存在');
        }


        // 创建model
        $this->createModel($model_class, "plugin\\$plug_name\\app\\model", $model_file, $controller_name);

        // 创建controller
        $this->createController($controller_class, $controller_namespace, $controller_file, $model_class);

        return $this->json(0,'创建controller及model成功');
    }

    /**
     * 创建model
     *
     * @param $class
     * @param $namespace
     * @param $file
     * @param $table
     * @return void
     */
    protected function createModel($class, $namespace, $file, $table)
    {
        $this->mkdir($file);
        $table_val = "'$table'";
        $pk = 'id';
        $properties = '';
        $timestamps = '';
        $columns = [];
        try {
            $database = config('database.connections')['plugin.admin.mysql']['database'];
            //plugin.admin.mysql
            foreach (Util::db()->select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
                if ($item->COLUMN_KEY === 'PRI') {
                    $pk = $item->COLUMN_NAME;
                    $item->COLUMN_COMMENT .= "(主键)";
                }
                $type = $this->getType($item->DATA_TYPE);
                $properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
                $columns[$item->COLUMN_NAME] = $item->COLUMN_NAME;
            }
        } catch (\Throwable $e) {}
        if (!isset($columns['created_at']) || !isset($columns['updated_at'])) {
            $timestamps = <<<EOF
/**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public \$timestamps = false;
EOF;

        }
        $properties = rtrim($properties) ?: ' *';
        $model_content = <<<EOF
<?php

namespace $namespace;

use plugin\admin\app\model\BaseThink;
/**
$properties
 */
class $class extends BaseThink
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected \$table = $table_val;

    /**
     * The primary key associated with the table.
     *
     * @var string
     */
    protected \$pk = '$pk';
    
    $timestamps
    
    /**
     * 可写入字段
     */
    protected \$field = [];
    /**
     * 显示隐藏字段
     * \$visible=['name']
     */
    protected \$hidden = [];
    /**
     * 设置模型中json类型字段
     */
    protected \$json = [];
    /**
     * 自动验证规则
     */
    protected \$validate=[
        'rule'=>[
            'nickname' => 'require'
        ],
        'msg'=>[
            'nickname.require'     => '昵称不能为空',
        ]
    ];
}

EOF;
        file_put_contents($file, $model_content);
    }

    /**
     * 创建控制器
     *
     * @param $controller_class
     * @param $namespace
     * @param $file
     * @param $model_class
     * @param $name
     * @return void
     */
    protected function createController($controller_class, $namespace, $file, $model_class)
    {
        $this->mkdir($file);
        $controller_content = <<<EOF
<?php

namespace $namespace;

use plugin\admin\app\controller\Base;
use plugin\admin\app\controller\common\Crud;
use plugin\admin\app\common\\xbuilder\\XBuilderForm;
use plugin\admin\app\common\\xbuilder\\XBuilderList;
use plugin\\admin\\app\\model\\$model_class;
use support\Request;

class $controller_class extends Base
{
    /**
     * 开启增删改查 
     */
    use Crud;
    
    /**
     * @var $model_class
     */
    protected \$model = null;

    /**
     * 构造函数
     * 
     * @return void
     */
    public function __construct()
    {
        \$this->model = new $model_class;
    }

    /**
     * 获取列表数据
     */
     public function index(){
        \$builder = new XBuilderList();
        return \$builder->setMetaTitle(' ') // 设置页面标题
        ->addTopButton('add',\$this->add())
            ->addTopButton('forbid')
            ->addTopButton('recycle')
            ->addTopButton('restore')
            ->addTopButton('delete')
            ->addTableColumn('id', 'ID','',false,true)
            ->addTableColumn('status', '状态', 'status')
            ->addTableColumn('created_at', '创建时间', 'datetime')
            ->addRightButton('edit',\$this->edit()) // 添加编辑弹窗按钮
            ->addRightButton('forbid') // 添加编辑按钮
            ->addRightButton('resume') // 添加编辑按钮
            ->addRightButton('recycle') // 添加编辑按钮
            ->addRightButton('restore') // 添加编辑按钮
            ->addRightButton('delete') // 添加编辑按钮
            ->setTableApi()
            ->getPageData();
    }
    public function add()
    {
        return \$this->form('add');
    }
    public function edit()
    {
        return \$this->form('edit');
    }
    protected function form(\$type = 'add')
    {
        if (request()->method() == 'POST') {
            \$slider_object = \$this->model;
            \$data  = request()->except(['create_at']);
            if(isset(\$data['password']) && \$data['password'])
            if(\$type === 'add'){
                \$result=\$slider_object->save(\$data);
            } else {
                \$result=\$slider_object->update(\$data);
            }
            if (\$result) {
                return \$this->resSucess('操作成功');
            } else {
                return \$this->resError('操作失败');
            }
        } else {
            \$statusOpt = [  //单选
                'type'=>'select',
                'options'=>[
                    ['label'=>'未审核', 'value'=>'0'], ['label'=>'驳回', 'value'=>'-1'], ['label'=>'审核', 'value'=>'1']
                ]
            ];
            \$emailRule = [
                'required'=>true,
                'rule'=>[
                    'isEmail'=>true
                ],
                'errMsg'=>[
                    'isNumeric'=>'邮箱格式错误',
                ]
            ];
            \$telRule = [
                'required'=>true,
                'rule'=>[
                    'matchRegexp'=>'/^[1][3,4,5,7,8,9][0-9]{9}$/'
                ],
                'errMsg'=>[
                    'matchRegexp'=>'请输入正确的手机号码',
                ]
            ];
            \$builder = new XBuilderForm();
            return \$builder->setMetaTitle('编辑管理员信息')
                ->setFormUrl(\$type)
                ->setFormMode('horizontal')
                ->addFormItem('username', 'text', '用户名', true)
                ->addFormItem('nickname', 'text', '昵称',true)
                ->addFormItem('password', 'password', '密码')
                ->addFormItem('avatar', 'image','头像')
                ->addFormItem('email', 'text','邮箱',\$emailRule)
                ->addFormItem('mobile', 'text','手机号码',\$telRule)
                ->addFormItem('status', \$statusOpt,'状态')
                ->setFooterAffix()
                ->getFormData();
        }
    }
}

EOF;
        file_put_contents($file, $controller_content);
    }

    protected function mkdir($file)
    {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }
    }

    /**
     * 字段类型到php类型映射
     *
     * @param string $type
     * @return string
     */
    protected function getType(string $type)
    {
        if (strpos($type, 'int') !== false) {
            return 'integer';
        }
        switch ($type) {
            case 'varchar':
            case 'string':
            case 'text':
            case 'date':
            case 'time':
            case 'guid':
            case 'datetimetz':
            case 'datetime':
            case 'decimal':
            case 'enum':
                return 'string';
            case 'boolean':
                return 'integer';
            case 'float':
                return 'float';
            default:
                return 'mixed';
        }
    }

}
